bitkeeper revision 1.1108.33.39 (410f5c80HHs32Qoh3S41tB5KdiU-uA)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 3 Aug 2004 09:36:00 +0000 (09:36 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 3 Aug 2004 09:36:00 +0000 (09:36 +0000)
Fix pci_alloc_consistent() to always return contiguous
machine memory.

linux-2.4.26-xen-sparse/arch/xen/kernel/pci-dma.c
linux-2.4.26-xen-sparse/mkbuildtree

index dd8842719e5a41132c11b4ca6a3250a9a4883063..e841ba86ca1ff011161959f865659d5eee3a8124 100644 (file)
@@ -18,15 +18,59 @@ void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
 {
        void *ret;
        int gfp = GFP_ATOMIC;
+       unsigned int order = get_order(size);
+       unsigned long vstart;
 
        if (hwdev == NULL || ((u32)hwdev->dma_mask < 0xffffffff))
                gfp |= GFP_DMA;
-       ret = (void *)__get_free_pages(gfp, get_order(size));
 
-       if (ret != NULL) {
-               memset(ret, 0, size);
-               *dma_handle = virt_to_bus(ret);
+       ret = (void *)vstart = __get_free_pages(gfp, order);
+       if (ret == NULL)
+               return ret;
+
+       /*
+        * Ensure multi-page extents are contiguous in machine memory.
+        * This code could be cleaned up some, and the number of
+        * hypercalls reduced.
+        */
+       if (size > PAGE_SIZE) {
+               pgd_t         *pgd; 
+               pmd_t         *pmd;
+               pte_t         *pte;
+               unsigned long  pfn, i;
+               /* 1. Zap current PTEs, giving away the underlying pages. */
+               for (i = 0; i < (1<<order); i++) {
+                       pgd = pgd_offset_k(   (vstart + (i*PAGE_SIZE)));
+                       pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE)));
+                       pte = pte_offset(pmd, (vstart + (i*PAGE_SIZE)));
+                       pfn = pte->pte_low >> PAGE_SHIFT;
+                       queue_l1_entry_update(pte, 0);
+                       flush_page_update_queue();
+                       if (HYPERVISOR_dom_mem_op(MEMOP_decrease_reservation, 
+                               &pfn, 1, 0) != 1) BUG();
+               }
+               /* 2. Get a new contiguous memory extent. */
+               if (HYPERVISOR_dom_mem_op(MEMOP_increase_reservation,
+                       &pfn, 1, order) != 1) BUG();
+               /* 3. Map the new extent in place of old pages. */
+               for (i = 0; i < (1<<order); i++) {
+                       pgd = pgd_offset_k(   (vstart + (i*PAGE_SIZE)));
+                       pmd = pmd_offset(pgd, (vstart + (i*PAGE_SIZE)));
+                       pte = pte_offset(pmd, (vstart + (i*PAGE_SIZE)));
+                       queue_l1_entry_update(pte, 
+                               ((pfn+i)<<PAGE_SHIFT)|__PAGE_KERNEL);
+                       queue_machphys_update(pfn+i,
+                               (__pa(ret)>>PAGE_SHIFT)+i);
+                       phys_to_machine_mapping[(__pa(ret)>>PAGE_SHIFT)+i] =
+                               pfn+i;
+                        flush_page_update_queue();
+               }
+               flush_page_update_queue();
        }
+
+       memset(ret, 0, size);
+       *dma_handle = virt_to_bus(ret);
+
        return ret;
 }
 
index 3dd6515b887fd14902b6de473221e841e5a855a3..bb06d9b97856e9e8ff00b548492ad778b1d4cdd5 100755 (executable)
@@ -213,7 +213,6 @@ ln -sf ../../${LINUX_26}/include/asm-xen/xen_proc.h
 cd ${AD}/arch/xen/kernel
 ln -sf ../../i386/kernel/i387.c
 ln -sf ../../i386/kernel/init_task.c
-ln -sf ../../i386/kernel/pci-dma.c
 ln -sf ../../i386/kernel/pci-i386.c
 ln -sf ../../i386/kernel/pci-i386.h
 ln -sf ../../i386/kernel/ptrace.c